// defineReactive 数据绑定响应
class HistoryRoute {
  constructor() {
    this.current = null;
  }
}
class vueRouter {
  constructor(options) {
    this.mode = options.mode || "hash";
    this.routes = options.routes || [];
    this.routesMap = this.createMap(this.routes);
    this.history = new HistoryRoute();
    this.init();
  }
  init() {
    if (this.mode === "hash") {
      // 没有输入hash时自动加#
      if (!location.hash) {
        location.hash = "/";
      }
      window.addEventListener("load", () => {
        this.history.current = location.hash.slice(1);
      });
      window.addEventListener("hashchange", () => {
        this.history.current = location.hash.slice(1);
      });
    }
  }
  createMap(routes) {
    // 适当地变化数据结构：把数组转化成对象，key为path
    return routes.reduce((memo, current) => {
      memo[current.path] = current.component;
      return memo;
    }, {});
  }
}
vueRouter.install = function(vue) {
  if (vueRouter.install.installed) return; // 单例模式
  vueRouter.install.installed = true;
  // 执行顺序：main => app.vue => 组件
  vue.mixin({
    beforeCreate() {
      if (this.$options && this.$options.router) {
        // router只有main中有
        // Vue2.0：new Vue({el:'#app',router,components:{App},template:'<App />'})
        this._root = this;
        this._router = this.$options.router;
        vue.util.defineReactive(this, "current", this._router.history);
      } else if (this.$parent) {
        // app.vue
        this._root = this.$parent._root; // 让每个组件都有_root且始终指向main中的实例
      }
      // this.$router this.$route
      // 变量权限思维：不设置set，不可更改
      // 用Proxy和defineProperty区别：defineProperty是更改this；Proxy是代理this，形成新的对象
      Object.defineProperty(this, "$router", {
        get() {
          return this._root._router;
        }
      });
      Object.defineProperty(this, "$route", {
        get() {
          return this._root._router.history.current;
        }
      });
    }
  });
  // current改变 => 重新渲染 => render中获取current => 对应current组件
  vue.component("router-view", {
    name: "RouterView",
    // functional: true,
    render(h) {
      // let h = ref.parent.$createElement;
      let current = this._self._root._router.history.current;
      let routerMap = this._self._root._router.routesMap;
      return h(routerMap[current]);
    }
  });
};
export default vueRouter;
